use moparse_lib::{Cli, VerilogParser};
use moparse_lib::cli::Commands;
use moparse_lib::shell::{ShellExecutor, CsvParams};
use anyhow::Result;

fn main() -> Result<()> {
    let cli = Cli::parse_args();
    
    match cli.command {
        Commands::Parse { verilog, filelist, output, existing, module, all } => {
            handle_parse(verilog, filelist, output, existing, module, all)?;
        }
        
        Commands::Show { input, module, verbose } => {
            handle_show(input, module, verbose)?;
        }
        
        Commands::Delete { input, module } => {
            handle_delete(&input, &module)?;
        }
        
        Commands::Hierarchy { input, module, level, output } => {
            handle_hierarchy(&input, &module, level, output.as_deref())?;
        }
        
        Commands::Generate { input, module, output, mode } => {
            handle_generate(&input, &module, output.as_deref(), &mode)?;
        }
        
        Commands::Compare { input, module, reference, ref_module } => {
            handle_compare(&input, &module, &reference, ref_module.as_deref())?;
        }
        
        Commands::Connect { input, module, from, from_top, feedthrough, to, to_top, tie, signal, verbose, exclude, group, source, output, source_inplace, debug, sort, csv, ft_type, pass_instances, clock, reset, reset_to, port_format, port_format_auto, repeater_module } => {
            handle_connect(&input, &module, from.as_deref(), from_top, &feedthrough, to.as_deref(), to_top, tie.as_deref(), signal.as_deref(), verbose, &exclude, group, source.as_deref(), output.as_deref(), source_inplace.as_deref(), debug, sort, csv.as_deref(), ft_type.as_deref(), pass_instances.as_deref(), clock.as_deref(), reset.as_deref(), reset_to.as_deref(), port_format.as_deref(), port_format_auto, repeater_module.as_deref())?;
        }
        
        Commands::Shell { input, script, sort, csv, ft_type, pass_instances, clock, reset, reset_to, port_format, port_format_auto, repeater_module } => {
            handle_shell(&input, script.as_deref(), sort, csv.as_deref(), ft_type.as_deref(), pass_instances.as_deref(), clock.as_deref(), reset.as_deref(), reset_to.as_deref(), port_format.as_deref(), port_format_auto, repeater_module.as_deref())?;
        }
    }
    
    Ok(())
}

fn handle_parse(
    verilog: Option<String>,
    filelist: Option<String>,
    output: Option<String>,
    existing: Option<String>,
    module: Option<String>,
    all: bool,
) -> Result<()> {
    // Use regex-based parser
    handle_parse_regex(output, existing, module, all, filelist, verilog)?;
    
    Ok(())
}

fn handle_parse_regex(
    output: Option<String>,
    existing: Option<String>,
    module: Option<String>,
    all: bool,
    filelist: Option<String>,
    verilog: Option<String>,
) -> Result<()> {
    let mut parser = VerilogParser::new();
    
    // Parse files
    if let Some(vfile) = verilog {
        let mod_name = if all { None } else { module.as_deref() };
        parser.parse_verilog_file(&vfile, mod_name)?;
    } else if let Some(flist) = filelist {
        let mod_name = if all { None } else { module.as_deref() };
        parser.parse_verilog_file_list(&flist, mod_name)?;
    } else {
        eprintln!("Error: Need to specify input file (-v or -f)");
        std::process::exit(1);
    }
    
    // Save results
    if let Some(out) = output {
        parser.save_to_modb(&out)?;
        println!("Successfully saved to: {}", out);
    } else if let Some(exist) = existing {
        parser.merge_to_modb(&exist)?;
        println!("Successfully merged to: {}", exist);
    } else {
        eprintln!("Error: Need to specify output file (-o or -e)");
        std::process::exit(1);
    }
    
    Ok(())
}

fn handle_show(input: Option<String>, module: Option<String>, verbose: u8) -> Result<()> {
    if let Some(f) = input {
        let mut parser = VerilogParser::new();
        parser.load_from_modb(&f)?;
        parser.show_module_info(module.as_deref(), verbose);
        Ok(())
    } else {
        eprintln!("Error: Need to specify .modb file (-i)");
        std::process::exit(1);
    }
}

fn handle_delete(input: &str, module: &str) -> Result<()> {
    let mut parser = VerilogParser::new();
    parser.load_from_modb(input)?;
    
    // TODO: Implement delete functionality
    println!("Delete module functionality not yet implemented: {}", module);
    
    Ok(())
}

fn handle_hierarchy(input: &str, module: &str, level: usize, output: Option<&str>) -> Result<()> {
    let mut parser = VerilogParser::new();
    parser.load_from_modb(input)?;
    parser.show_hierarchy(module, level, output)?;
    Ok(())
}

fn handle_generate(input: &str, module: &str, output: Option<&str>, mode: &str) -> Result<()> {
    let mut parser = VerilogParser::new();
    parser.load_from_modb(input)?;
    generate_verilog_code(&mut parser, module, output, mode)?;
    Ok(())
}

/// Generate Verilog code (public for shell mode)
pub fn generate_verilog_code(parser: &mut VerilogParser, module: &str, output: Option<&str>, mode: &str) -> Result<()> {
    // Get the module from database
    let db = parser.database();
    let target_module = db.modules.iter()
        .find(|m| m.name == module)
        .ok_or_else(|| anyhow::anyhow!("Module '{}' not found in database", module))?;
    
    // Generate Verilog code based on mode
    let verilog_code = match mode {
        "e" => generate_empty_shell(target_module),
        "es" => generate_empty_shell_with_stub(target_module),
        "a" => generate_full_module(target_module),
        "i" => generate_instance(target_module),
        _ => return Err(anyhow::anyhow!("Invalid mode: {}. Use 'e', 'es', 'a', or 'i'", mode)),
    };
    
    // Write to output file or print to stdout
    if let Some(out) = output {
        std::fs::write(out, verilog_code)?;
        println!("Successfully generated Verilog code to: {}", out);
    } else {
        print!("{}", verilog_code);
    }
    
    Ok(())
}

/// Generate empty shell (only module declaration and ports)
fn generate_empty_shell(module: &moparse_lib::proto::Module) -> String {
    let mut code = String::new();
    
    // Module header
    code.push_str(&format!("module {} (\n", module.name));
    
    // Group ports by their ifdef attribute
    let mut current_ifdef = String::new();
    
    for (i, port) in module.ports.iter().enumerate() {
        // Handle ifdef context changes
        if port.attribute != current_ifdef {
            // Close previous ifdef if any
            if !current_ifdef.is_empty() {
                code.push_str("`endif\n");
            }
            // Open new ifdef if needed
            if !port.attribute.is_empty() {
                code.push_str(&format!("{}\n", port.attribute));
            }
            current_ifdef = port.attribute.clone();
        }
        
        let comma = if i < module.ports.len() - 1 { "," } else { "" };
        if port.width.is_empty() {
            code.push_str(&format!("    {}{}\n", port.name, comma));
        } else {
            code.push_str(&format!("    {}{}\n", port.name, comma));
        }
    }
    
    // Close final ifdef if any
    if !current_ifdef.is_empty() {
        code.push_str("`endif\n");
    }
    
    code.push_str(");\n\n");
    
    // Port declarations
    current_ifdef = String::new();
    for port in &module.ports {
        // Handle ifdef context changes
        if port.attribute != current_ifdef {
            // Close previous ifdef if any
            if !current_ifdef.is_empty() {
                code.push_str("`endif\n");
            }
            // Open new ifdef if needed
            if !port.attribute.is_empty() {
                code.push_str(&format!("{}\n", port.attribute));
            }
            current_ifdef = port.attribute.clone();
        }
        
        if port.width.is_empty() {
            code.push_str(&format!("    {} {};\n", port.direction, port.name));
        } else {
            code.push_str(&format!("    {} {} {};\n", port.direction, port.width, port.name));
        }
    }
    
    // Close final ifdef if any
    if !current_ifdef.is_empty() {
        code.push_str("`endif\n");
    }
    
    code.push_str("\nendmodule\n");
    code
}

/// Extract module shell (declaration + ports) from original code
fn extract_module_shell(module_code: &str, module_name: &str) -> String {
    let mut result = String::new();
    let lines: Vec<&str> = module_code.lines().collect();
    
    let mut in_port_section = false;
    let mut brace_count = 0;
    let mut found_module = false;
    
    for line in lines {
        let trimmed = line.trim();
        
        // Check for module declaration
        if trimmed.starts_with("module") && trimmed.contains(module_name) {
            found_module = true;
            result.push_str(line);
            result.push('\n');
            
            // Check if port list starts on same line
            if line.contains('(') {
                in_port_section = true;
                brace_count += line.matches('(').count() as i32;
                brace_count -= line.matches(')').count() as i32;
                
                if brace_count == 0 {
                    in_port_section = false;
                }
            }
            continue;
        }
        
        // If we're in the port section
        if found_module && !in_port_section && line.contains('(') && !trimmed.starts_with("input") && !trimmed.starts_with("output") && !trimmed.starts_with("inout") {
            in_port_section = true;
            brace_count += line.matches('(').count() as i32;
            brace_count -= line.matches(')').count() as i32;
            result.push_str(line);
            result.push('\n');
            
            if brace_count == 0 {
                in_port_section = false;
            }
            continue;
        }
        
        if in_port_section {
            result.push_str(line);
            result.push('\n');
            
            brace_count += line.matches('(').count() as i32;
            brace_count -= line.matches(')').count() as i32;
            
            if brace_count == 0 {
                in_port_section = false;
                // We've finished the port list, now look for port declarations
                continue;
            }
        }
        
        // After port list, capture port declarations (input/output/inout) until first non-port line
        if found_module && !in_port_section && brace_count == 0 {
            if trimmed.starts_with("input") || trimmed.starts_with("output") || trimmed.starts_with("inout") ||
               trimmed.starts_with("`ifdef") || trimmed.starts_with("`ifndef") || 
               trimmed.starts_with("`else") || trimmed.starts_with("`endif") {
                result.push_str(line);
                result.push('\n');
            } else if !trimmed.is_empty() && !trimmed.starts_with("//") {
                // Hit non-port declaration, stop
                break;
            } else if trimmed.is_empty() || trimmed.starts_with("//") {
                // Keep empty lines and comments in port section
                result.push_str(line);
                result.push('\n');
            }
        }
    }
    
    result.push_str("\nendmodule\n");
    result
}

/// Generate empty shell with stub (output ports tied to 0)
fn generate_empty_shell_with_stub(module: &moparse_lib::proto::Module) -> String {
    let mut code = generate_empty_shell(module);
    
    // Insert tie-offs before endmodule
    let endmodule_pos = code.rfind("endmodule").unwrap();
    let mut tie_code = String::new();
    
    // Group output ports by their ifdef attribute
    let mut current_ifdef = String::new();
    
    for port in &module.ports {
        if port.direction == "output" {
            // Handle ifdef context changes
            if port.attribute != current_ifdef {
                // Close previous ifdef if any
                if !current_ifdef.is_empty() {
                    tie_code.push_str("`endif\n");
                }
                // Open new ifdef if needed
                if !port.attribute.is_empty() {
                    tie_code.push_str(&format!("{}\n", port.attribute));
                }
                current_ifdef = port.attribute.clone();
            }
            
            let tie_value = if port.width.is_empty() {
                "1'b0".to_string()
            } else {
                calculate_tie_value(&port.width)
            };
            tie_code.push_str(&format!("    assign {} = {};\n", port.name, tie_value));
        }
    }
    
    // Close final ifdef if any
    if !current_ifdef.is_empty() {
        tie_code.push_str("`endif\n");
    }
    
    if !tie_code.is_empty() {
        tie_code.push('\n');
    }
    
    code.insert_str(endmodule_pos, &tie_code);
    code
}

/// Extract module shell with output port tie-offs from original code
fn extract_module_shell_with_tie(module_code: &str, module_name: &str) -> String {
    let lines: Vec<&str> = module_code.lines().collect();
    
    // Phase 1: Extract module declaration and port declarations
    let mut shell_lines = Vec::new();
    let mut output_ports = Vec::new(); // (port_name, width, ifdef_context)
    
    let mut found_module = false;
    let mut in_port_list = false;
    let mut port_list_done = false;
    let mut paren_count = 0;
    let mut ifdef_stack = Vec::new();
    
    for line in &lines {
        let trimmed = line.trim();
        
        // Track ifdef/ifndef/else/endif
        if trimmed.starts_with("`ifdef") || trimmed.starts_with("`ifndef") {
            ifdef_stack.push(line.to_string());
        } else if trimmed.starts_with("`else") {
            if let Some(last) = ifdef_stack.last_mut() {
                *last = line.to_string();
            }
        } else if trimmed.starts_with("`endif") {
            ifdef_stack.pop();
        }
        
        // Find module declaration
        if !found_module {
            if trimmed.starts_with("module") && (trimmed.contains(module_name) || 
                trimmed == &format!("module {}", module_name) || 
                trimmed.starts_with(&format!("module {}(", module_name))) {
                found_module = true;
                shell_lines.push(line.to_string());
                
                // Check if port list starts on same line
                if line.contains('(') {
                    in_port_list = true;
                    paren_count = line.matches('(').count() as i32 - line.matches(')').count() as i32;
                    if paren_count == 0 {
                        in_port_list = false;
                        port_list_done = true;
                    }
                }
                continue;
            }
        }
        
        // If we found module but haven't started port list yet, look for opening paren
        if found_module && !in_port_list && !port_list_done {
            shell_lines.push(line.to_string());
            if line.contains('(') {
                in_port_list = true;
                paren_count = line.matches('(').count() as i32 - line.matches(')').count() as i32;
                if paren_count == 0 {
                    in_port_list = false;
                    port_list_done = true;
                }
            }
            continue;
        }
        
        // Handle port list (in parentheses after module name)
        if found_module && in_port_list {
            shell_lines.push(line.to_string());
            paren_count += line.matches('(').count() as i32 - line.matches(')').count() as i32;
            if paren_count == 0 {
                in_port_list = false;
                port_list_done = true;
            }
            continue;
        }
        
        // After port list, collect port declarations
        if found_module && port_list_done {
            // Port declaration or preprocessor directive
            if trimmed.starts_with("input") || trimmed.starts_with("inout") {
                shell_lines.push(line.to_string());
            } else if trimmed.starts_with("output") {
                shell_lines.push(line.to_string());
                // Extract output port info
                if let Some((name, width)) = parse_output_port(line) {
                    output_ports.push((name, width, ifdef_stack.clone()));
                }
            } else if trimmed.starts_with("`ifdef") || trimmed.starts_with("`ifndef") ||
                      trimmed.starts_with("`else") || trimmed.starts_with("`endif") {
                shell_lines.push(line.to_string());
            } else if trimmed.is_empty() || trimmed.starts_with("//") {
                shell_lines.push(line.to_string());
            } else if !trimmed.is_empty() {
                // Hit non-port declaration
                break;
            }
        }
    }
    
    // Build result
    let mut result = shell_lines.join("\n");
    result.push_str("\n\n");
    
    // Generate tie-offs for output ports
    let mut prev_ifdef_stack: Vec<String> = Vec::new();
    
    for (port_name, width, ifdef_context) in &output_ports {
        // Determine what ifdef directives need to change
        // Close ifdefs that are no longer needed
        while prev_ifdef_stack.len() > ifdef_context.len() {
            result.push_str("`endif\n");
            prev_ifdef_stack.pop();
        }
        
        // Update ifdef stack to match current context
        for (i, ifdef_line) in ifdef_context.iter().enumerate() {
            if i >= prev_ifdef_stack.len() || &prev_ifdef_stack[i] != ifdef_line {
                // Close old ifdefs from this point
                while prev_ifdef_stack.len() > i {
                    result.push_str("`endif\n");
                    prev_ifdef_stack.pop();
                }
                // Open new ifdef
                result.push_str(ifdef_line);
                result.push('\n');
                prev_ifdef_stack.push(ifdef_line.clone());
            }
        }
        
        // Generate assign statement
        let tie_value = if width.is_empty() {
            "1'b0".to_string()
        } else {
            calculate_tie_value(width)
        };
        result.push_str(&format!("    assign {} = {};\n", port_name, tie_value));
    }
    
    // Close all remaining ifdef blocks
    while !prev_ifdef_stack.is_empty() {
        result.push_str("`endif\n");
        prev_ifdef_stack.pop();
    }
    
    result.push_str("\nendmodule\n");
    result
}

/// Parse output port declaration to extract name and width
fn parse_output_port(port_line: &str) -> Option<(String, String)> {
    let trimmed = port_line.trim();
    if !trimmed.starts_with("output") {
        return None;
    }
    
    // Remove "output" and optional "wire" or "reg"
    let mut after_output = trimmed.strip_prefix("output")?.trim();
    after_output = after_output.strip_prefix("wire").unwrap_or(after_output).trim();
    after_output = after_output.strip_prefix("reg").unwrap_or(after_output).trim();
    
    // Handle multi-dimensional arrays like [2:0][17:0]
    let mut width = String::new();
    let mut rest = after_output;
    
    // Collect all dimensions
    while rest.starts_with('[') {
        if let Some(end_bracket) = rest.find(']') {
            if width.is_empty() {
                width.push_str(&rest[..=end_bracket]);
            } else {
                width.push_str(&rest[..=end_bracket]);
            }
            rest = rest[end_bracket + 1..].trim();
        } else {
            break;
        }
    }
    
    // Extract port name (before semicolon or comma)
    let name = rest.split(|c| c == ';' || c == ',')
        .next()?
        .trim()
        .to_string();
    
    Some((name, width))
}

/// Calculate tie value based on width
fn calculate_tie_value(width: &str) -> String {
    if width.is_empty() {
        return "1'b0".to_string();
    }
    
    // Handle multi-dimensional arrays like [2:0][17:0]
    // Find the rightmost dimension for bit width
    let dimensions: Vec<&str> = width.split(']')
        .filter(|s| !s.is_empty())
        .map(|s| s.trim_start_matches('[').trim())
        .collect();
    
    if dimensions.is_empty() {
        return "1'b0".to_string();
    }
    
    // Use the last (rightmost) dimension for the bit width
    let last_dim = dimensions.last().unwrap();
    
    if last_dim.contains(':') {
        let parts: Vec<&str> = last_dim.split(':').collect();
        if parts.len() == 2 {
            if let (Ok(msb), Ok(lsb)) = (parts[0].trim().parse::<i32>(), parts[1].trim().parse::<i32>()) {
                let bit_count = (msb - lsb).abs() + 1;
                
                // If there are multiple dimensions, calculate total elements
                if dimensions.len() > 1 {
                    // For multi-dimensional, we just tie the element count to match
                    let mut total_elements = 1;
                    for dim in &dimensions[..dimensions.len()-1] {
                        if dim.contains(':') {
                            let dim_parts: Vec<&str> = dim.split(':').collect();
                            if dim_parts.len() == 2 {
                                if let (Ok(m), Ok(l)) = (dim_parts[0].trim().parse::<i32>(), dim_parts[1].trim().parse::<i32>()) {
                                    total_elements *= (m - l).abs() + 1;
                                }
                            }
                        }
                    }
                    return format!("{}'b0", total_elements);
                } else {
                    return format!("{}'b0", bit_count);
                }
            }
        }
    }
    
    "1'b0".to_string()
}

/// Generate full module (using stored info if available)
fn generate_full_module(module: &moparse_lib::proto::Module) -> String {
    // If we have the original module code stored, use it
    if !module.info.is_empty() && module.info.starts_with("module") {
        return module.info.clone();
    }
    
    // Otherwise, generate from parsed data
    let mut code = String::new();
    
    // Module header
    code.push_str(&format!("module {} (\n", module.name));
    
    // Ports
    for (i, port) in module.ports.iter().enumerate() {
        let comma = if i < module.ports.len() - 1 { "," } else { "" };
        if port.width.is_empty() {
            code.push_str(&format!("    {} {}{}\n", port.direction, port.name, comma));
        } else {
            code.push_str(&format!("    {} {} {}{}\n", port.direction, port.width, port.name, comma));
        }
    }
    
    code.push_str(");\n\n");
    
    // Parameters
    if !module.parameters.is_empty() {
        for param in &module.parameters {
            if param.value.is_empty() {
                code.push_str(&format!("    parameter {};\n", param.name));
            } else {
                code.push_str(&format!("    parameter {} = {};\n", param.name, param.value));
            }
        }
        code.push_str("\n");
    }
    
    // Wires
    if !module.wires.is_empty() {
        for wire in &module.wires {
            if wire.width.is_empty() {
                code.push_str(&format!("    wire {};\n", wire.name));
            } else {
                code.push_str(&format!("    wire {} {};\n", wire.width, wire.name));
            }
        }
        code.push_str("\n");
    }
    
    // Instances
    if !module.instances.is_empty() {
        for inst in &module.instances {
            code.push_str(&format!("    {} {} (\n", inst.module_name, inst.name));
            
            // Port connections
            for (i, port_conn) in inst.port_connections.iter().enumerate() {
                let comma = if i < inst.port_connections.len() - 1 { "," } else { "" };
                code.push_str(&format!("        .{}({}){}\n", 
                    port_conn.port_name, port_conn.signal_expr, comma));
            }
            
            code.push_str("    );\n\n");
        }
    }
    
    code.push_str("endmodule\n");
    
    code
}

/// Generate instance template (for instantiating this module)
fn generate_instance(module: &moparse_lib::proto::Module) -> String {
    let mut code = String::new();
    
    code.push_str(&format!("// Instance template for module {}\n\n", module.name));
    
    // First, declare wires for all ports
    let mut current_ifdef = String::new();
    
    for port in &module.ports {
        // Handle ifdef context changes
        if port.attribute != current_ifdef {
            // Close previous ifdef if any
            if !current_ifdef.is_empty() {
                code.push_str("`endif\n");
            }
            // Open new ifdef if needed
            if !port.attribute.is_empty() {
                code.push_str(&format!("{}\n", port.attribute));
            }
            current_ifdef = port.attribute.clone();
        }
        
        // Declare wire with same name as port
        if port.width.is_empty() {
            code.push_str(&format!("wire {};\n", port.name));
        } else {
            code.push_str(&format!("wire {} {};\n", port.width, port.name));
        }
    }
    
    // Close final ifdef if any
    if !current_ifdef.is_empty() {
        code.push_str("`endif\n");
    }
    
    code.push_str("\n");
    
    // Calculate max port name length for alignment
    let max_port_len = module.ports.iter()
        .map(|p| p.name.len())
        .max()
        .unwrap_or(0);
    
    // Generate instance with port connections
    code.push_str(&format!("{} u_{} (\n", module.name, module.name.to_lowercase()));
    
    // Reset ifdef tracking for port connections
    current_ifdef = String::new();
    
    for (i, port) in module.ports.iter().enumerate() {
        // Handle ifdef context changes
        if port.attribute != current_ifdef {
            // Close previous ifdef if any
            if !current_ifdef.is_empty() {
                code.push_str("`endif\n");
            }
            // Open new ifdef if needed
            if !port.attribute.is_empty() {
                code.push_str(&format!("{}\n", port.attribute));
            }
            current_ifdef = port.attribute.clone();
        }
        
        let comma = if i < module.ports.len() - 1 { "," } else { "" };
        // Align the opening parenthesis
        code.push_str(&format!("    .{:<width$} ({}){}\n", 
            port.name, 
            port.name, 
            comma,
            width = max_port_len));
    }
    
    // Close final ifdef if any
    if !current_ifdef.is_empty() {
        code.push_str("`endif\n");
    }
    
    code.push_str(");\n");
    
    code
}

fn handle_compare(input: &str, module: &str, reference: &str, ref_module: Option<&str>) -> Result<()> {
    let mut parser1 = VerilogParser::new();
    parser1.load_from_modb(input)?;
    
    let mut parser2 = VerilogParser::new();
    parser2.load_from_modb(reference)?;
    
    let ref_mod = ref_module.unwrap_or(module);
    
    // Get modules from both databases
    let db1 = parser1.database();
    let db2 = parser2.database();
    
    let module1 = db1.modules.iter()
        .find(|m| m.name == module)
        .ok_or_else(|| anyhow::anyhow!("Module '{}' not found in first database", module))?;
    
    let module2 = db2.modules.iter()
        .find(|m| m.name == ref_mod)
        .ok_or_else(|| anyhow::anyhow!("Module '{}' not found in second database", ref_mod))?;
    
    println!("\nModule Comparison");
    println!("{}", "=".repeat(100));
    println!("{:<50} | {:<47}", 
        format!("Module 1: {} ({})", module, input),
        format!("Module 2: {} ({})", ref_mod, reference));
    println!("{}", "=".repeat(100));
    
    let mut has_differences = false;
    
    // Compare parameters
    println!("\n[Parameters]");
    println!("{}", "-".repeat(100));
    
    let mut param_has_diff = false;
    
    if module1.parameters.is_empty() && module2.parameters.is_empty() {
        println!("  No parameters in either module");
    } else {
        // Collect all unique parameter names
        let mut all_param_names: std::collections::HashSet<String> = std::collections::HashSet::new();
        for p in &module1.parameters {
            all_param_names.insert(p.name.clone());
        }
        for p in &module2.parameters {
            all_param_names.insert(p.name.clone());
        }
        
        let mut param_names: Vec<String> = all_param_names.into_iter().collect();
        param_names.sort();
        
        // Check if there are any differences
        for param_name in &param_names {
            let param1 = module1.parameters.iter().find(|p| &p.name == param_name);
            let param2 = module2.parameters.iter().find(|p| &p.name == param_name);
            
            let differs = match (param1, param2) {
                (Some(p1), Some(p2)) => p1.value != p2.value,
                _ => true,
            };
            
            if differs {
                if !param_has_diff {
                    println!("{:<50} | {:<47}", "Module 1", "Module 2");
                    println!("{}", "-".repeat(100));
                    param_has_diff = true;
                }
                
                let left = if let Some(p1) = param1 {
                    format!("{} = {}", p1.name, if p1.value.is_empty() { "<none>" } else { &p1.value })
                } else {
                    String::new()
                };
                
                let right = if let Some(p2) = param2 {
                    format!("{} = {}", p2.name, if p2.value.is_empty() { "<none>" } else { &p2.value })
                } else {
                    String::new()
                };
                
                println!("  {:<48} | {:<47}", left, right);
                has_differences = true;
            }
        }
        
        if !param_has_diff {
            println!("  All parameters match");
        }
    }
    
    // Compare ports
    println!("\n[Ports]");
    println!("{}", "-".repeat(100));
    
    let mut port_has_diff = false;
    
    if module1.ports.is_empty() && module2.ports.is_empty() {
        println!("  No ports in either module");
    } else {
        // Calculate column widths using statistics
        let dir_width = 6;  // "output" is longest
        let width1 = module1.max_port_width_len.max(5) as usize;  // Minimum 5 for "[x:0]"
        let width2 = module2.max_port_width_len.max(5) as usize;
        let name1 = module1.max_port_name_len.max(10) as usize;  // Minimum 10
        let name2 = module2.max_port_name_len.max(10) as usize;
        
        // Collect all unique port names
        let mut all_port_names: std::collections::HashSet<String> = std::collections::HashSet::new();
        for p in &module1.ports {
            all_port_names.insert(p.name.clone());
        }
        for p in &module2.ports {
            all_port_names.insert(p.name.clone());
        }
        
        let mut port_names: Vec<String> = all_port_names.into_iter().collect();
        port_names.sort();
        
        // Check if there are any differences
        for port_name in &port_names {
            let port1 = module1.ports.iter().find(|p| &p.name == port_name);
            let port2 = module2.ports.iter().find(|p| &p.name == port_name);
            
            let differs = match (port1, port2) {
                (Some(p1), Some(p2)) => p1.direction != p2.direction || p1.width != p2.width,
                _ => true,
            };
            
            if differs {
                if !port_has_diff {
                    // Print column headers with proper alignment
                    let hdr1 = format!("{:<dir$} {:<w$} {:<n$}", "Dir", "Width", "Name",
                        dir = dir_width, w = width1, n = name1);
                    let hdr2 = format!("{:<dir$} {:<w$} {:<n$}", "Dir", "Width", "Name",
                        dir = dir_width, w = width2, n = name2);
                    println!("  {:<48} | {:<47}", hdr1, hdr2);
                    println!("{}", "-".repeat(100));
                    port_has_diff = true;
                }
                
                // Format left side (Module 1)
                let left = if let Some(p1) = port1 {
                    let w = if p1.width.is_empty() { "" } else { &p1.width };
                    format!("{:<dir$} {:<w$} {:<n$}", p1.direction, w, p1.name,
                        dir = dir_width, w = width1, n = name1)
                } else {
                    String::new()
                };
                
                // Format right side (Module 2)
                let right = if let Some(p2) = port2 {
                    let w = if p2.width.is_empty() { "" } else { &p2.width };
                    format!("{:<dir$} {:<w$} {:<n$}", p2.direction, w, p2.name,
                        dir = dir_width, w = width2, n = name2)
                } else {
                    String::new()
                };
                
                println!("  {:<48} | {:<47}", left, right);
                has_differences = true;
            }
        }
        
        if !port_has_diff {
            println!("  All ports match");
        }
    }
    
    // Compare instances
    println!("\n[Instances]");
    println!("{}", "-".repeat(100));
    
    let mut inst_has_diff = false;
    
    if module1.instances.is_empty() && module2.instances.is_empty() {
        println!("  No instances in either module");
    } else {
        // Collect all unique instance names
        let mut all_inst_names: std::collections::HashSet<String> = std::collections::HashSet::new();
        for i in &module1.instances {
            all_inst_names.insert(i.name.clone());
        }
        for i in &module2.instances {
            all_inst_names.insert(i.name.clone());
        }
        
        let mut inst_names: Vec<String> = all_inst_names.into_iter().collect();
        inst_names.sort();
        
        // Check if there are any differences
        for inst_name in &inst_names {
            let inst1 = module1.instances.iter().find(|i| &i.name == inst_name);
            let inst2 = module2.instances.iter().find(|i| &i.name == inst_name);
            
            let differs = match (inst1, inst2) {
                (Some(i1), Some(i2)) => i1.module_name != i2.module_name || i1.port_connections.len() != i2.port_connections.len(),
                _ => true,
            };
            
            if differs {
                if !inst_has_diff {
                    println!("{:<50} | {:<47}", "Module 1", "Module 2");
                    println!("{}", "-".repeat(100));
                    inst_has_diff = true;
                }
                
                let left = if let Some(i1) = inst1 {
                    format!("{} ({})", i1.name, i1.module_name)
                } else {
                    String::new()
                };
                
                let right = if let Some(i2) = inst2 {
                    format!("{} ({})", i2.name, i2.module_name)
                } else {
                    String::new()
                };
                
                println!("  {:<48} | {:<47}", left, right);
                has_differences = true;
            }
        }
        
        if !inst_has_diff {
            println!("  All instances match");
        }
    }
    
    // Final summary
    println!("\n{}", "=".repeat(100));
    if has_differences {
        println!("Result: Modules DIFFER");
    } else {
        println!("Result: Modules are IDENTICAL");
    }
    println!("{}", "=".repeat(100));
    println!();
    
    Ok(())
}

fn handle_connect(
    input: &str,
    module: &str,
    from: Option<&str>,
    from_top: bool,
    feedthrough: &[String],
    to: Option<&str>,
    to_top: bool,
    tie: Option<&str>,
    signal: Option<&str>,
    verbose: bool,
    exclude: &[String],
    group: bool,
    source: Option<&str>,
    output: Option<&str>,
    source_inplace: Option<&str>,
    debug: bool,
    sort: bool,
    csv: Option<&str>,
    ft_type: Option<&str>,
    pass_instances: Option<&str>,
    clock: Option<&str>,
    reset: Option<&str>,
    reset_to: Option<&str>,
    port_format: Option<&str>,
    port_format_auto: bool,
    repeater_module: Option<&str>,
) -> Result<()> {
    let mut parser = VerilogParser::new();
    parser.load_from_modb(input)?;
    
    // Initialize CSV file if specified
    if let Some(csv_file) = csv {
        // Write header if file doesn't exist
        if !std::path::Path::new(csv_file).exists() {
            std::fs::write(
                csv_file,
                "ft_type,src_path,pass_instances,dst_path,port_format,clock,reset,reset_to,repeater_module\n",
            )?;
        }
    }
    
    // ... existing code ...
    let (final_source, final_output) = if let Some(inplace_file) = source_inplace {
        // -po takes precedence over -p and -o
        (Some(inplace_file), Some(inplace_file))
    } else {
        (source, output)
    };
    
    if let Some(signal_name) = signal {
        parser.show_signal_connections(module, signal_name)?;
    } else {
        parser.show_signal_trace(module, from, from_top, feedthrough, to, to_top, tie, verbose, exclude, group, final_source, final_output, debug, sort)?;
        
        // If CSV is enabled, record the connection
        if let Some(csv_file) = csv {
            let csv_params = CsvParams::new(ft_type, pass_instances, clock, reset, reset_to, port_format, port_format_auto, repeater_module);
            write_csv_for_connection(csv_file, &parser, module, from, to, &csv_params, feedthrough)?;
        }
    }
    
    Ok(())
}

/// Helper function to write connection record to CSV file
fn write_csv_for_connection(csv_file: &str, parser: &VerilogParser, module: &str, from: Option<&str>, to: Option<&str>, csv_params: &CsvParams, feedthrough: &[String]) -> Result<()> {
    if from.is_none() || to.is_none() {
        return Ok(());
    }
    
    let from_inst = from.unwrap();
    let to_inst = to.unwrap();
    
    // Get the module from database
    let db = parser.database();
    let top_module = db.modules.iter()
        .find(|m| m.name == module)
        .ok_or_else(|| anyhow::anyhow!("Module '{}' not found", module))?;
    
    // Find the from and to instances
    // Need to use parser's resolve_hierarchical_path function for nested paths
    // For simple paths (no dots), directly search in top module
    // For hierarchical paths (with dots), need to navigate through modules
    
    let (from_context, from_name) = if from_inst.contains('.') {
        // Hierarchical path - need to navigate to parent module
        let parts: Vec<&str> = from_inst.split('.').collect();
        if parts.is_empty() {
            return Ok(());
        }
        let mut current_module = top_module;
        // Navigate to the parent of the last instance
        for i in 0..parts.len() - 1 {
            let inst_name = parts[i];
            let inst = current_module.instances.iter().find(|inst| inst.name == inst_name)
                .ok_or_else(|| anyhow::anyhow!("Instance {} not found", inst_name))? ;
            let next_mod = db.modules.iter().find(|m| m.name == inst.module_name)
                .ok_or_else(|| anyhow::anyhow!("Module {} not found", inst.module_name))? ;
            current_module = next_mod;
        }
        (current_module, parts[parts.len() - 1])
    } else {
        (top_module, from_inst.as_ref())
    };
    
    let (to_context, to_name) = if to_inst.contains('.') {
        // Hierarchical path - need to navigate to parent module
        let parts: Vec<&str> = to_inst.split('.').collect();
        if parts.is_empty() {
            return Ok(());
        }
        let mut current_module = top_module;
        // Navigate to the parent of the last instance
        for i in 0..parts.len() - 1 {
            let inst_name = parts[i];
            let inst = current_module.instances.iter().find(|inst| inst.name == inst_name)
                .ok_or_else(|| anyhow::anyhow!("Instance {} not found", inst_name))? ;
            let next_mod = db.modules.iter().find(|m| m.name == inst.module_name)
                .ok_or_else(|| anyhow::anyhow!("Module {} not found", inst.module_name))? ;
            current_module = next_mod;
        }
        (current_module, parts[parts.len() - 1])
    } else {
        (top_module, to_inst.as_ref())
    };
    
    let from_inst_obj = from_context.instances.iter().find(|inst| inst.name == from_name);
    let to_inst_obj = to_context.instances.iter().find(|inst| inst.name == to_name);
    
    if let (Some(from_obj), Some(to_obj)) = (from_inst_obj, to_inst_obj) {
        // Get module definitions for both instances
        let from_module_def = db.modules.iter().find(|m| m.name == from_obj.module_name);
        let to_module_def = db.modules.iter().find(|m| m.name == to_obj.module_name);
        
        if let (Some(from_mod), Some(to_mod)) = (from_module_def, to_module_def) {
            // Default values
            let ft_type = csv_params.ft_type.as_deref().unwrap_or("signal");
            let pass_instances = csv_params.pass_instances.as_deref().unwrap_or("");
            let clock = csv_params.clock.as_deref().unwrap_or("clk");
            let reset = csv_params.reset.as_deref().unwrap_or("rst_n:0");
            let reset_to = csv_params.reset_to.as_deref().unwrap_or("0");
            let port_format = csv_params.port_format.as_deref().unwrap_or("");
            let repeater_module = csv_params.repeater_module.as_deref().unwrap_or("");
            
            // Process connections: match port names between instances
            for from_port_conn in &from_obj.port_connections {
                // Find matching connection in to_inst
                for to_port_conn in &to_obj.port_connections {
                    // Check if they're connected via the same signal
                    if from_port_conn.signal_expr == to_port_conn.signal_expr && !from_port_conn.signal_expr.is_empty() {
                        // Get port definitions to determine direction
                        let from_port_def = from_mod.ports.iter().find(|p| p.name == from_port_conn.port_name);
                        let to_port_def = to_mod.ports.iter().find(|p| p.name == to_port_conn.port_name);
                        
                        if let (Some(from_port), Some(to_port)) = (from_port_def, to_port_def) {
                            // Determine source and destination based on port directions
                            let (src_path, dst_path) = if from_port.direction == "output" && to_port.direction == "input" {
                                // from is source, to is destination
                                let src = if from_port.width.is_empty() {
                                    format!("{}.{}", from_inst, from_port_conn.port_name)
                                } else {
                                    format!("{}.{} {}", from_inst, from_port_conn.port_name, from_port.width)
                                };
                                let dst = if to_port.width.is_empty() {
                                    format!("{}.{}", to_inst, to_port_conn.port_name)
                                } else {
                                    format!("{}.{} {}", to_inst, to_port_conn.port_name, to_port.width)
                                };
                                (src, dst)
                            } else if from_port.direction == "input" && to_port.direction == "output" {
                                // to is source, from is destination
                                let src = if to_port.width.is_empty() {
                                    format!("{}.{}", to_inst, to_port_conn.port_name)
                                } else {
                                    format!("{}.{} {}", to_inst, to_port_conn.port_name, to_port.width)
                                };
                                let dst = if from_port.width.is_empty() {
                                    format!("{}.{}", from_inst, from_port_conn.port_name)
                                } else {
                                    format!("{}.{} {}", from_inst, from_port_conn.port_name, from_port.width)
                                };
                                (src, dst)
                            } else {
                                // Skip input-input or output-output connections
                                continue;
                            };
                            
                            // Write to CSV file in append mode
                            use std::fs::OpenOptions;
                            use std::io::Write;
                            let mut file = OpenOptions::new()
                                .write(true)
                                .append(true)
                                .open(csv_file)?;
                            
                            // Determine port_format value
                            let effective_port_format = if csv_params.port_format_auto {
                                // Use the wire name (signal expression)
                                from_port_conn.signal_expr.clone()
                            } else {
                                port_format.to_string()
                            };
                            
                            // Determine pass_instances value
                            let effective_pass_instances = if pass_instances.is_empty() && !feedthrough.is_empty() {
                                // If no explicit pass_instances provided and we have feedthrough modules,
                                // this is a feedthrough chain, so pass_instances should be empty
                                String::new()
                            } else {
                                // For direct connections, check connection direction
                                if from_port.direction == "input" && to_port.direction == "output" {
                                    // input→output connection: reverse the pass_instances order
                                    if !pass_instances.is_empty() {
                                        pass_instances.split('|').rev().collect::<Vec<_>>().join("|")
                                    } else {
                                        pass_instances.to_string()
                                    }
                                } else {
                                    // output→input connection or no pass_instances: use as-is
                                    pass_instances.to_string()
                                }
                            };
                            
                            // Format: ft_type,src_path,pass_instances,dst_path,port_format,clock,reset,reset_to,repeater_module
                            let mut csv_line = String::new();
                            csv_line.push_str(&format!("{},", ft_type));
                            csv_line.push_str(&format!("{},", src_path));
                            csv_line.push_str(&format!("{},", effective_pass_instances));
                            csv_line.push_str(&format!("{},", dst_path));
                            csv_line.push_str(&format!("{},", effective_port_format));
                            csv_line.push_str(&format!("{},", clock));
                            csv_line.push_str(&format!("{},", reset));
                            csv_line.push_str(&format!("{},", reset_to));
                            csv_line.push_str(&format!("{}", repeater_module));
                            writeln!(file, "{}", csv_line)?;
                        }
                    }
                }
            }
        }
    }
    
    Ok(())
}

fn handle_shell(
    input: &str,
    script: Option<&str>,
    sort: bool,
    csv: Option<&str>,
    ft_type: Option<&str>,
    pass_instances: Option<&str>,
    clock: Option<&str>,
    reset: Option<&str>,
    reset_to: Option<&str>,
    port_format: Option<&str>,
    port_format_auto: bool,
    repeater_module: Option<&str>,
) -> Result<()> {
    let csv_params = CsvParams::new(ft_type, pass_instances, clock, reset, reset_to, port_format, port_format_auto, repeater_module);
    let mut executor = ShellExecutor::new(input, sort, csv, &csv_params)?;
    
    if let Some(script_file) = script {
        // Batch mode
        executor.run_batch(script_file)?;
    } else {
        // Interactive mode
        executor.run_interactive()?;
    }
    
    Ok(())
}
